/**
    Copyright (C) 2011  Alexander Vollmer

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.jefb.service.impl;

import java.util.List;

import org.jefb.dao.ICommonDao;
import org.jefb.entity.DestinationEntity;
import org.jefb.entity.FileDestEntity;
import org.jefb.entity.dto.FileToken;
import org.jefb.entity.dto.TransmissionCallback;
import org.jefb.sec.service.ITransInitService;
import org.jefb.service.INIOService;
import org.jefb.service.IRemoteProxy;
import org.jefb.service.ISenderService;
import org.jefb.util.JefbUtils;
import org.jefb.util.service.impl.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class SenderService implements ISenderService {
	
	private static Logger log = LoggerFactory.getLogger(SenderService.class);

	// services
	// util services
	@Autowired
	private Config config;
	// business services
	@Autowired
	private ICommonDao commonDAO;
	@Autowired
	private ITransInitService transInitService;
	@Autowired
	private INIOService nioService;

	/**
	 * Sends all marked for transmission files.
	 */
	public void send() {
		// obtain all
		FileDestEntity example = new FileDestEntity();
		example.setTransmitted(false);
		List<FileDestEntity> foundTokens = commonDAO.findByExample(example);
		for (FileDestEntity fileDestinationEntity : foundTokens) {
			if (!fileDestinationEntity.getFile().getDirectory()) {
				DestinationEntity destination = fileDestinationEntity.getDestination();
				IRemoteProxy remoteProxy = transInitService
						.getReceiver(destination);
				if (remoteProxy == null) {
					// TODO receiver unavalable, log and go to the next entity
					continue;
				}
				// FIXME dangerous loop, break after some iterations
				while (!fileDestinationEntity.getTransmitted()) {
					FileToken fileToken = new FileToken();

					// prepare data for transmission
					//String fileName = fileDestinationEntity.getFile().getPath()+JefbUtils.FILE_SEPARATOR+fileDestinationEntity.getFile().getName();
					String absoluteFileName =
						fileDestinationEntity.getFile().getWorkspace()+
						fileDestinationEntity.getFile().getPath()+
						JefbUtils.FILE_SEPARATOR+fileDestinationEntity.getFile().getName();
					fileToken.setSenderAgentId(config.getAgentId());
					fileToken.setFilename(fileDestinationEntity.getFile().getName());
					fileToken.setPath(fileDestinationEntity.getFile().getPath());
					fileToken.setFileLength(fileDestinationEntity.getFile().getSize());
					fileToken.setOffset(fileDestinationEntity.getOffset());
					nioService.readToken(fileToken, absoluteFileName);

					FileToken preparedToken = transInitService.prepareToken(
							fileToken, destination);

					// transmit data
					TransmissionCallback transmissionCallback = remoteProxy
							.receive(preparedToken);
					if (transmissionCallback.isTransmissionSucceed()) {
						// calculate new offset
						fileDestinationEntity.setOffset(fileToken.getOffset()
								+ fileToken.getLength());
						if (fileToken.getFileLength() <= fileToken.getOffset()
								+ config.getMaxTokenLength()) {
							// TODO implement proper transmission check
							// receiverService.getTransmissionStatus(dto);
							// ask receiver service to confirm successful
							// transmission (MD5)
							fileDestinationEntity.setTransmitted(true);
						}
						writeTransmissionStatus(fileDestinationEntity);
					}
				}
			}
		}
	}

	@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
	private void writeTransmissionStatus(FileDestEntity fileDestEntity) {
		commonDAO.merge(fileDestEntity);
	}

	public void setNioService(INIOService nioService) {
		this.nioService = nioService;
	}

	public INIOService getNioService() {
		return nioService;
	}

	public void setTransInitService(ITransInitService transInitService) {
		this.transInitService = transInitService;
	}

	public ITransInitService getTransInitService() {
		return transInitService;
	}

	public void setConfig(Config config) {
		this.config = config;
	}

	public Config getConfig() {
		return config;
	}

	public void setCommonDAO(ICommonDao commonDAO) {
		this.commonDAO = commonDAO;
	}

	public ICommonDao getCommonDAO() {
		return commonDAO;
	}

}
